package val.to;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import android.location.Location;
import android.util.Log;
import val.to.SessionEvents.LogoutListener;
import val.to.config.Constants;
import val.to.entities.DisplayMode;
import val.to.entities.Event;
import val.to.entities.EventState;
import val.to.entities.FeedFilterType;
import val.to.entities.PhotoPost;
import val.to.server.IServerPortal;
import val.to.server.RESTServerPortal;
import val.to.server.IServerPortal.FeedUpdate;

public class ValtoServices {
	
	private static Event currentEvent;
	private static Object lockObj = new Object();
    private static IServerPortal _portal = new RESTServerPortal();    
    private static ArrayList<ICurrentEventChangeListener> s_listeners = new ArrayList<ICurrentEventChangeListener>();
    private static HashMap<Integer, EventState> sm_eventStates = new HashMap<Integer, EventState>();	
    private static Date lastUpdate = null;
    
    static {
    	initialize();
	}
    
    public interface ICurrentEventChangeListener{
    	void onEventChanged();
    	void onSameEventSelected();
    }
    
    public static void addEventChangedListener(ICurrentEventChangeListener listener){
    	s_listeners.add(listener);
    }
    
    //For off-line testing, use:
    //private static IServerPortal _portal = new TestServerPortal();
    
    public static String getLastServerError(){
    	return _portal.getLastError();
    }
    
    public static void selectEvent(Event event){
 
    	//TODO: access currentEvent safely
    	if (event == null && currentEvent != null){
    		//Will ocure on case of logout.
    		synchronized (lockObj) {
    			currentEvent = null;	
			}    		
    		Log.d("ValtoServices", "Selected event was set to <NULL>");
	
    		onSelectedEventChanged();
    		return;
    	}
    	
    	if (event == null && currentEvent == null){
    		//Do nothing in such case
    		return;
    	}
    	
    	
    	if (!event.equals(currentEvent)){
    		synchronized (lockObj) {
    			currentEvent = event;
    		}
    		Log.d("ValtoServices", "Selected event changed: " + event.toString());
    		
    		onSelectedEventChanged();
    	}
    	else{
    		for(ICurrentEventChangeListener l : s_listeners){
    			l.onSameEventSelected();
    		}	
    	}
    }
    
    private static void onSelectedEventChanged(){
    	lastUpdate = null;
		for(ICurrentEventChangeListener l : s_listeners){
			l.onEventChanged();
		}	
    }
    
    public static ArrayList<Event> getEvents(Location location){ 
    	ArrayList<Event> events = _portal.getEvents(location);
    	if (events != null){
    		for(Event event : events){
    			EventState state = getEventState(event.getId(), true);
    			(event.new StateSync()).doSync(state);
    		}
    	}
    	
    	return events;
    }
    
    public static ArrayList<Event> getOwnerEvents() {
		return _portal.getOwnerEvents();
	}
    
	public static ArrayList<String> getFriendsListCheckedInEvent(int eventId) {
		return _portal.getFriendsListCheckedInEvent(eventId);
	}

    public static FeedUpdate getFeedItems(Date refDate, int maxItems, boolean forward, FeedFilterType filter){ 
    	if (currentEvent == null){   		
    		Log.w(Constants.TAG, "Trying to get feed items when no active event selected");
    		return null;
    	}
    	
    	FeedUpdate update = _portal.getFeedItems(currentEvent.getId(), refDate, lastUpdate, maxItems, forward, filter);
    	if (update == null){
    		return null;
    	}
    	
    	lastUpdate = update.lastUpdate;
    	return update;
    }
    
    public static boolean postEvent(Event event){
    	if (!_portal.postEvent(event)){
    		return false;
    	}
    	
		EventState state = getEventState(event.getId(), true);
		(event.new StateSync()).doSync(state);
    	return true;
    }
    
    public static boolean updateEvent(Event updatedEvent) {
		return _portal.updateEvent(updatedEvent);
	}
    
    public static boolean exportEvent(Event event) {
    	return _portal.exportEvent(event);
	}

	public static boolean deleteEvent(Event existingEvent) {
		if  (!_portal.deleteEvent(existingEvent)){
			return false;
		}
		
		deleteEventState(existingEvent.getId());
		return true;
	}
    
    public static boolean postPhoto(PhotoPost photo){
    	if (currentEvent == null){
       		Log.w(Constants.TAG, "Trying to post a photo when no active event selected");
    		return false;
    	}
    	
    	int currentEventId = currentEvent.getId();
    	if (_portal.postPhoto(photo, currentEventId)){
    		//Photo upload => check into current event
        	EventState state = getEventState(currentEventId, true);
        	state.checkedIn = true;
    		return true;
    	}
    	
    	return false;
    }
    
    public static boolean deletePhoto(int photoId){
    	if (currentEvent == null){
       		Log.w(Constants.TAG, "Trying to delete a photo when no active event selected");
    		return false;
    	}
    	
    	return _portal.deletePhoto(currentEvent.getId(), photoId);
    }
    
    public static boolean checkIntoCurrentEvent(boolean notifyServer){
    	if (currentEvent == null){
       		Log.w(Constants.TAG, "Trying to check into event when no active event selected");
    		return false;
    	}
    	
    	int currentEventId = currentEvent.getId();
    	if (notifyServer && !_portal.checkIntoEvent(currentEventId)){
    		return false;
    	}
    	
    	EventState state = getEventState(currentEventId, true);
    	state.checkedIn = true;
    	return true;
    }
    
    public static boolean isCheckedIntoEvent(int eventId){
    	EventState state = getEventState(eventId, false);
    	return state != null && state.checkedIn;
    }
    
    public static boolean shareEvent(int eventId){
     	if (!_portal.shareEvent(eventId)){
    		return false;
    	}
    	
    	EventState state = getEventState(eventId, true);
    	state.shared = true;
    	return true;
    }
    
    public static boolean isEventShared(int eventId){
    	EventState state = getEventState(eventId, false);
    	return state != null && state.shared;
    }
    
    
    public static boolean setFilterType(int eventId, FeedFilterType filter){
    	EventState state = getEventState(eventId, true);
    	if (state.filter != filter){
    		state.filter = filter;
    		return true;
    	}
    	return false;
    }
    
    public static FeedFilterType getFilterType(int eventId){
    	EventState state = getEventState(eventId, false);
    	if (state == null){
    		return FeedFilterType.None; //default
    	}
    	
    	return state.filter;
    }
    
    public static DisplayMode nextDisplayMode(int eventId){
    	EventState state = getEventState(eventId, true);
    	if (state == null){
    		return DisplayMode.NewsFeed;
    	}
    	
    	if (state.displayMode == DisplayMode.Album){
    		state.displayMode = DisplayMode.NewsFeed;
    	}
    	else{
    		state.displayMode = DisplayMode.Album;
    	}
    	
    	return state.displayMode;
    }
    
    public static void SetDisplayMode(Event event, DisplayMode displayMode)
    {
    	EventState state = getEventState(event.getId(), true);
    	state.displayMode = displayMode;
    }    
    
    public static DisplayMode getDisplayMode(int eventId){
    	EventState state = getEventState(eventId, false);
    	return state != null ? state.displayMode : DisplayMode.NewsFeed;
    }
    
    private static EventState getEventState(int eventId, boolean addIfNoExist){
     	synchronized (sm_eventStates) {
	    	EventState state = sm_eventStates.get(eventId);
	    	if (state == null && addIfNoExist){
	  
	    		state = new EventState();
	    		sm_eventStates.put(eventId, state);
	    	}
	    	   	
	     	return state; 	
     	}
    }
    
    
    private static void deleteEventState(int eventId){
     	synchronized (sm_eventStates) {
     		sm_eventStates.remove(eventId);
     	}
    }
    
    public static void initialize(){
    	SessionEvents.addLogoutListener(new LogoutListener() {			
			public void onLogoutFinish() {
				selectEvent(null);
				synchronized (sm_eventStates) {
					sm_eventStates.clear();	
				}
			
				Globals.clear();
			}
			
			public void onLogoutBegin() {		
			}
		});
    }
    
    public static Event getCurrentEvent(){
    	synchronized (lockObj) {
    		return currentEvent;
		}
    }
}
